<template>
  <!-- 图片预览 -->
  <div v-if="fileType === fileCategory.image">
    <ElImageViewer
      :url-list="[previewUrl]"
      :initial-index="0"
      hide-on-click-modal
      close-on-press-escape
      @close="visible = false"
    />
  </div>
  <Window
    v-else
    :visible="visible"
    :width="800"
    :title="filename"
    @close="visible = false"
  >
    <!-- 文件不支持预览时显示 -->
    <div v-if="!supported" class="unsupported-file">
      <ElIcon :size="64">
        <Document />
      </ElIcon>
      <p>此文件类型不支持预览</p>
      <ElButton type="primary" @click="handleDownload">下载文件</ElButton>
    </div>

    <!-- 文件加载中 -->
    <div v-else-if="loading" class="loading-container">
      <ElIcon class="is-loading" :size="64">
        <Loading />
      </ElIcon>
    </div>

    <!-- 文本文件预览 -->
    <div v-else-if="fileType === fileCategory.text" class="text-preview">
      <pre>{{ textContent }}</pre>
    </div>

    <!-- Excel 预览 -->
    <div
      v-else-if="fileType === fileCategory.excel"
      class="excel-preview"
      v-html="excelContent"
    ></div>

    <!-- PDF预览 -->
    <iframe
      v-else-if="fileType === fileCategory.pdf"
      class="h95"
      :src="previewUrl"
      frameborder="0"
      width="100%"
    ></iframe>

    <!-- 视频预览、文档预览 -->
    <div
      ref="previewContainer"
      class="h95"
      :style="{
        display: [fileCategory.video, fileCategory.doc].includes(fileType)
          ? 'block'
          : 'none',
        overflowY: 'scroll'
      }"
    ></div>

    <!-- 音频预览 -->
    <div
      ref="audioContainer"
      :style="{
        display: fileType === fileCategory.audio ? 'block' : 'none',
        width: '100%'
      }"
    ></div>
  </Window>
</template>

<script setup>
import { ref, onMounted, watch, onUnmounted } from 'vue'
import { Document, Loading } from '@element-plus/icons-vue'
import { URLS } from '@/constants'
import { PlainMessage } from '@/utils'
import DPlayer from 'dplayer'
import { renderAsync } from 'docx-preview'
import APlayer from 'APlayer'
import { BASE_URL } from '@/utils/api'
import Window from './window.vue'
import service from '@/utils/api'
import * as XLSX from 'xlsx'
import { determineFileType, fileCategory } from '@/utils'

const visible = defineModel('modelValue')

const props = defineProps({
  fileId: {
    type: [Number, String],
    required: true
  },
  filename: {
    type: String,
    required: true
  }
})

const loading = ref(true)
const supported = ref(true)
const previewUrl = ref('')
const fileType = ref('')
const textContent = ref('')
const previewContainer = ref(null)
let playerInstance = null
const excelContent = ref('')
const audioContainer = ref(null)

// 加载文件预览
const loadFilePreview = async () => {
  try {
    loading.value = true

    fileType.value = determineFileType(props.filename)
    // 生成预览URL
    const token = localStorage.getItem('token')
    previewUrl.value = `${BASE_URL}${URLS.FILE_PREVIEW.replace(
      ':id',
      props.fileId
    )}?token=${token}`

    // 根据文件类型处理预览逻辑
    switch (fileType.value) {
      case fileCategory.image:
      case fileCategory.pdf:
        break
      case fileCategory.video:
        if (playerInstance) {
          playerInstance.destroy()
          playerInstance = null
        }
        if (previewContainer.value) {
          try {
            playerInstance = new DPlayer({
              container: previewContainer.value,
              video: {
                url: previewUrl.value,
                type: 'auto'
              },
              autoplay: false
            })
          } catch (error) {
            console.error('创建视频播放器失败:', error)
            supported.value = false
          }
        } else {
          console.error('视频容器元素不存在')
          supported.value = false
        }
        break
      case fileCategory.text:
        const { data } = await service.get(previewUrl.value)
        textContent.value = data
        break
      case fileCategory.doc: {
        const { data } = await service.get(previewUrl.value, {
          responseType: 'arraybuffer'
        })

        try {
          await renderAsync(data, previewContainer.value)
        } catch (error) {
          console.error('渲染文档失败:', error)
          supported.value = false
        }
        break
      }
      case fileCategory.excel: {
        const res = await service.get(previewUrl.value, {
          responseType: 'arraybuffer'
        })
        if (!res) return

        const workbook = XLSX.read(new Uint8Array(res.data), { type: 'array' })
        const worksheet = workbook.Sheets[workbook.SheetNames[0]]
        excelContent.value = XLSX.utils.sheet_to_html(worksheet)
        break
      }
      case fileCategory.audio: {
        playerInstance = new APlayer({
          container: audioContainer.value,
          audio: {
            url: previewUrl.value,
            name: props.filename
          }
        })
        break
      }
      default:
        supported.value = false
    }
  } catch (error) {
    console.error('预览文件失败:', error)
    PlainMessage.error('预览文件失败: ' + (error.message || '未知错误'))
    supported.value = false
  } finally {
    loading.value = false
  }
}

const handleDownload = () => {
  const token = localStorage.getItem('token')
  window.location.href = `${BASE_URL}${URLS.FILE_DOWNLOAD.replace(
    ':id',
    props.fileId
  )}?token=${token}`
}

onMounted(() => {
  loadFilePreview()
})

watch(
  () => props.fileId,
  newVal => {
    newVal && loadFilePreview()
  }
)

onUnmounted(() => {
  if (playerInstance) {
    playerInstance.destroy()
    playerInstance = null
  }
})
</script>

<style scoped>
.preview-container {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f5f7fa;
  overflow: auto;
}

.loading-container,
.unsupported-file {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
}

.loading-container p,
.unsupported-file p {
  margin: 20px 0;
  color: #606266;
  font-size: 16px;
}

.text-preview {
  width: 100%;
  height: 100%;
  padding: 20px;
  overflow: auto;
  background-color: white;
}

.text-preview pre {
  white-space: pre-wrap;
  word-wrap: break-word;
  font-family: monospace;
  font-size: 14px;
  line-height: 1.5;
}

.h95 {
  height: 95%;
}

:deep(.docx-wrapper) {
  min-height: 100%;
  padding: 0;
}

:deep(.docx) {
  height: 100% !important;
  box-shadow: none !important;
  margin-bottom: 0 !important;
}
.excel-preview {
  width: 100%;
}

:deep(table) {
  border-collapse: collapse;
}

:deep(td) {
  padding: 5px;
  border: 1px solid #000;
}
</style>
